home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-02 / extend5.zip / EXTEND.DOC < prev    next >
Text File  |  1990-11-19  |  14KB  |  245 lines

  1. (*
  2.                                   EXTEND.PAS
  3.                                   Release 5
  4.                               November 19, 1990
  5.                               by Scott Bussinger
  6.                              Compuserve 72247,2671
  7.  
  8.  
  9.   MS-DOS and PC-DOS Turbo Pascal 3.0 and higher only allow up to 15 files to
  10. be open at the same time, due to limitations in DOS.  This file shows you how
  11. to have up to 96 files open simultaneously under DOS 2.0 or 2.1, or 252 files
  12. open simultaneously under DOS 3.0 or higher.  Below is a description of how to
  13. use this technique, followed by a technical explanation of the implementation,
  14. for those who are interested.
  15.  
  16.   The implementation of this technique for DOS 2.X is based on a technique
  17. originally written by Randy Forgaard.  The interrupt handler and DOS 3.X
  18. implementation was written by Scott Bussinger with input and help from several
  19. others including Randy Forgaard, Bela Lubkin, Kim Kokkonen and Brian Foley.
  20.  
  21.   The early releases of this software used a traditional version numbering
  22. system (e.g. 1.1, 1.2, 2.1, etc.) and then I starting using TLIB (a source code
  23. control program) to manage the software and changed the numbering scheme to be
  24. compatible with that program.  The versions are now numbered sequentially with
  25. the first version (release 1) corresponding to the old version 3.2.  The
  26. documentation got so confusing that I've liberally re-editted the documentation
  27. files to eliminate the old references.  If anyone cares about the old comments
  28. and release history, grab an old copy of the source code and look there (it's
  29. not very interesting to anyone but me anyway).
  30.  
  31. TO USE THIS TECHNIQUE:
  32.  
  33.   You simply include the EXTEND unit in the USES statement in the source code
  34. of your main program.  You will have to either compile the EXTEND unit
  35. separately or use Turbo Pascal's project compiling features to Make or Build
  36. your program (which will compile the EXTEND unit automatically).  The
  37. EXTEND unit should be the first unit in your USES statement, following only
  38. the DOS unit (which is USEd by the EXTEND unit).  The unit automatically
  39. installs itself and will uninstall itself when your program ends or an error
  40. is detected.  See the demo program below for an example of using the EXTEND
  41. unit.
  42.  
  43.   The EXTEND.PAS file will need to be available available to be compiled if
  44. the Make or Build features are used to compile the program.  The EXTEND.ASM
  45. is the source code for the assembly language interrupt handler used when
  46. running under DOS 2.  The EXTEND.OBJ file is the assembled object code for
  47. EXTEND.ASM and was compiled using TASM.
  48.  
  49.   You must edit your CONFIG.SYS file (see the DOS manual for details), so
  50. that it includes a line that says "FILES=XXX".  XXX should be a number that is
  51. at least 3 greater than the maximum number of files that will be in use
  52. (opened by RESET, REWRITE or APPEND) at the same time during the execution of
  53. your program (larger values will provide no additional benefit, with respect
  54. to your individual program), and should not exceed 99 (for DOS 2.0/2.1) or 255
  55. (for DOS 3.0 and higher).  Under any version of DOS, the minimum allowable
  56. value for XXX is 8.  Then, reboot your computer so that the FILES=XXX
  57. parameter takes hold.  This same change to the CONFIG.SYS file will have to be
  58. made on any machine in which your program is to run.
  59.  
  60.   Running the sample program at the bottom of this file will tell you the
  61. maximum number of files you can have open at once (usually 3 less than the
  62. number of files specified in the CONFIG.SYS file as discussed above, unless a
  63. resident program has opened some files and hasn't closed them yet).
  64.  
  65. THE TECHNICAL DETAILS:
  66.  
  67.   Much of the following information is not documented in the DOS Technical
  68. Reference manual.
  69.  
  70.   Under DOS 1.0 and 1.1, all files were accessed via File Control Blocks
  71. (FCB's).  There was no limit to the number of FCB's that a program could use,
  72. so there was no limit to the number of files open simultaneously.
  73.  
  74.   Under DOS 2.0 and higher, an alternate (and preferable) method of accessing
  75. files was introduced, using a 2-byte integer called a "handle" to refer to a
  76. file.  A "handle" file is described using a data structure called a Device
  77. Control Block (DCB).  However, DOS provides the storage space for all DCB's,
  78. rather than having the application program store the DCB's, so the number of
  79. available DCB's is limited to the amount of space that DOS has set aside for
  80. them.  The maximum number of files/devices that can be open simultaneously, on
  81. the whole computer, is the number of slots available in the DCB Table created
  82. by DOS.  The DCB's in the DCB Table are consecutively numbered, starting with
  83. 0.  DCB's 0, 1, and 2 are predefined by DOS to correspond to the AUX, CON, and
  84. PRN devices, respectively.  All remaining DCB's in the DCB Table are available
  85. for files or devices used by application programs.
  86.  
  87.   So that I/O redirection can be supported, the DCB numbers are not used
  88. directly when accessing files.  Instead, a file "handle" is used.  A "handle"
  89. is an index into a 20-byte array, called the Handle Table, located at offset
  90. 18H of the Program Segment Prefix (PSP) for a program (for a general
  91. discussion of the PSP, see the DOS Technical Reference manual).  Each element
  92. of the Handle Table is the DCB number of a file or device.  The value at index
  93. "handle" in the Handle Table is the DCB number of the file or device that
  94. implements that file handle.  Thus, if the value 8 is in the 6th byte of the
  95. Handle Table, the handle "6" refers to the file (or device) described by the
  96. DCB in slot 8 of the DCB Table.  If a handle is not currently being used, its
  97. entry in the Handle Table is FFH.  DOS predefines the first 5 handles to be
  98. primary input, primary output, error, auxiliary, and printer, so the first 5
  99. entries in the Handle Table are 1, 1, 1, 0, and 2, corresponding to the DCB
  100. numbers for the CON (1), AUX (0), and PRN (2) devices.  This leaves only 15
  101. available handles for opening files (or new devices).
  102.  
  103.   Every time a new handle file is opened, a new handle gets used.  Since there
  104. are only 20 slots available in the Handle Table for a program, DOS only allows
  105. a "process" to have a maximum of 20 file handles in use simultaneously (and the
  106. first 5 entries are predefined, as just noted, unless those handles get closed
  107. and reused).  Every new handle file requires a unique handle, so only 20
  108. files/devices can be open at the same time by a single process (unless FCB's
  109. are used).  (A "process" is any program spawned using the DOS EXEC function
  110. call.  A process can be invoked by COMMAND.COM, or by another program.)  There
  111. can be many more than 20 DCB's in the DCB Table, so the real limitation is in
  112. the size of the Handle Table in the PSP.
  113.  
  114.   The size of the DCB Table (i.e., the maximum number of files/devices that
  115. can be open simultaneously in the whole computer) is controlled by the
  116. FILES=XXX entry in the CONFIG.SYS file.  The minimum number of slots is 8.
  117. Under DOS 2.0/2.1, the maximum number is 99, and under DOS 3.0 and higher,
  118. the maximum is 255.  As previously mentioned, the first three of these DCB
  119. slots are occupied by the AUX, CON, and PRN devices.
  120.  
  121.   A single program can use all of the DCB's in the DCB Table (except for the 3
  122. reserved by DOS) all on its own, by effectively bypassing the Handle Table in
  123. the PSP, except on a temporary basis.  The program can accomplish this feat by
  124. using, say, only one entry in the Handle Table for all of its files.  Instead
  125. of allowing DOS to store the DCB numbers in the Handle Table, the program can
  126. store these numbers elsewhere.  Then, to manipulate a file using DOS, the
  127. program can temporarily put the DCB number of that file into a designated slot
  128. in the Handle Table, pass the index of that table slot (i.e., that "handle")
  129. to DOS, and DOS will operate on that handle/DCB number.  After the DOS call,
  130. the program can remove that DCB number from the designated Handle Table slot,
  131. freeing up that handle for use in another DOS call for another file.  In this
  132. way, DOS can be fooled into accessing up to 96 (or 252) different files/devices
  133. using a single handle entry in the Handle Table.
  134.  
  135.   To obtain the address of the Handle Table, which is at offset 18H in the
  136. PSP, the program needs to find the address of its PSP.  Under Turbo Pascal
  137. 4.0 and later, the segment address of the PSP is stored in a pre-defined
  138. variable called PrefixSeg setup by Turbo's standard initialization code. All
  139. of the manipulation of the DCB's and handles is dealt with by ExtendHandler
  140. which is an interrupt handler which intercepts all DOS functions calls (INT
  141. 21) and checks to see if the function involves a handle number. If the
  142. function returns a handle (e.g. an Open File) it then returns the DCB to the
  143. calling program in place of a handle. It adds an constant offset of 5 to the
  144. DCB so that ExHandler can distinguish between DCB's and calls refering to the
  145. 5 automatically assigned standard handles. If the function invoked passes a
  146. handle to DOS (e.g. Read File) it checks to see if it refers to a standard
  147. handle and if so it passes control normally. If not, it subtracts the constant
  148. offset of 5 and temporarily usurps the use of handle 19. It places the DCB
  149. into the the slot in the handle table for handle 19 and changes the handle in
  150. the registers to 19. The previous DCB in handle 19 is saved and restored
  151. afterwards (this probably isn't necessary, but made me feel better).
  152.  
  153.   Note that these routines support all DOS functions up through DOS 3.3
  154. including those not normally used by Turbo.  The exception is function
  155. $46 (FORCEDUP). This call is rarely used, but incompatible with the methods
  156. used by ExHandler.  The only use that I know of for this function is to
  157. redirect the standard handles and since the standard handles are effectively
  158. skipped by these routines, there is no problem in using handles 0-4 as the
  159. second handle in a FORCEDUP call.  No other handles are allowed and will
  160. automatically result in an error being returned.  In other words, go ahead and
  161. redirect the standard handles, but don't try it with anything else.
  162.  
  163.   All of this hocus-pocus is required under DOS 2.X, but DOS 3.X is more
  164. intelligent and actually has some support for moving the handle table from the
  165. PSP to elsewhere in memory. So when running under DOS 3.0 to 3.2, the EXTEND
  166. unit uses a slightly documented capability to install a new, larger handle
  167. table. Essentially, Microsoft started to permit a standard way of creating a
  168. new handle table. This information is has been seen in at least one Microsoft
  169. document and has worked on every DOS I've seen or heard about. There are now
  170. two fields in the PSP which contain a pointer to the beginning of the handle
  171. table and a byte specifying the number of available handles. This method is
  172. much less kludgey and solves some problems with running programs under
  173. debuggers. The space for the new handle table is allocated out of free DOS
  174. memory (not in the memory allocated to the program by DOS when it started up
  175. the program). If no free memory is available, then the current program is
  176. shrunk down enough to allow the memory to be allocated. Using this memory
  177. solves problems with swapping EXEC programs and TSR's. When the program is
  178. finished, that memory is automatically released by DOS.
  179.  
  180.   As of DOS version 3.3, Microsoft actually added a real way to extend the
  181. number of handles available to a program and EXTEND.PAS takes advantage of
  182. that method when possible to ensure maximum compatibility in every
  183. environment.
  184.  
  185.   There is one incompatibility that I know of with EXTEND.  That is
  186. sub-functions 4 and 5 of DOS function $44 (IOCTL) when running under DOS 2.
  187. These calls send and receive control strings from block devices.  These two
  188. sub-functions use registers differently than all other sub-functions of IOCTL.
  189. I can't imagine a use for these two functions in a Pascal program, so I
  190. haven't bothered to modify the interrupt handler to identify this case.  If it
  191. is a problem, let me know and I may fix it.
  192.  
  193. *)
  194.  
  195. {  Example program  --  This program opens as many Text files as it can, until
  196.  DOS runs out of room in its DCB Table.  It then reports how many files were
  197.  successfully opened, writes a line to each of them, then closes and erases
  198.  each of them.  Note: The value of the FILES=XXX parameter in the CONFIG.SYS
  199.  file must be set to an appropriate value (see above).  If you change the
  200.  FILES=XXX value, be sure to reboot before running this program.
  201.  
  202.  This program takes a while to run, due to the heavy disk I/O, so running it on
  203.  a hard disk (or, even better, a RAM disk) is recommended.  Make sure that you
  204.  are running the program in a subdirectory, so that you don't run up against
  205.  the DOS limit on the number of allowable files in the root directory of a
  206.  drive. }
  207.  
  208. program Test;
  209.  
  210. uses Extend;       { <--- This is the magic line that does everything }
  211.  
  212. const MaxCount = 255;
  213.  
  214. type FileArray = array[1..MaxCount] of text;
  215.  
  216. var Count: integer;
  217.     F: ^FileArray;
  218.     I: integer;
  219.     Num: string[6];
  220.  
  221. begin
  222. new(F);            { Use heap because of large size of this array }
  223. writeln('Opening files...');
  224. I := 0;
  225. repeat
  226.   inc(I);
  227.   str(I,Num);
  228.   assign(F^[I],'junk' + num + '.txt');
  229.   {$I-}
  230.   rewrite(F^[I])
  231.   {$I+}
  232. until ioresult <> 0;
  233. Count := I - 1;
  234. writeln('Successfully opened ', Count, ' files at the same time.  Writing to each file...');
  235. for I := 1 to Count do
  236.   writeln(F^[I], 'This is a test.');
  237. writeln('Closing and erasing each file...');
  238. for I := 1 to Count do
  239.   begin
  240.   close(F^[I]);
  241.   erase(F^[I])
  242.   end;
  243. writeln('Done.')
  244. end.
  245.